package informationretrieval;

import static informationretrieval.Constants.NAME_ID;
import static informationretrieval.Constants.NAME_BODY;
import informationretrieval.extensions.MyTFIDFSimilarity;
import informationretrieval.extensions.StopwordAnalyzer;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.StopFilter;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.search.similarities.TFIDFSimilarity;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;

public class DocsDatabase {

	private final static String TAG = DocsDatabase.class.getSimpleName();
	public static final boolean DEV_MODE = true;
	private IndexWriter mIndexWriter;
	private Directory mIndex;
	private IndexSearcher mIndexSearcher;
	private IndexReader mIndexReader;
	private IndexWriterConfig mIndexWriterConfig;
	private Analyzer mAnalyzer = null;

	private int mTotalNumOfDocument = 0;
	private TFIDFSimilarity mTfidfSimilarity = new MyTFIDFSimilarity();

	public DocsDatabase(List<String> stopWordList,
			boolean usingImprovedAlgorithm) {
		try {
			if (usingImprovedAlgorithm) {
				mAnalyzer = new StopwordAnalyzer(Version.LUCENE_48,
						StopFilter.makeStopSet(Version.LUCENE_48, stopWordList));
			} else {
				mAnalyzer = new StandardAnalyzer(Version.LUCENE_48,
						StopFilter.makeStopSet(Version.LUCENE_48, stopWordList));
			}

			mIndexWriterConfig = new IndexWriterConfig(Version.LUCENE_48,
					mAnalyzer);
			mIndex = new RAMDirectory();

		} catch (Exception exception) {
			Log.error(TAG, exception, true);
		}
	}

	public void indexDocList(HashMap<String, String> docsList) {

		try {
			mIndexWriter = new IndexWriter(mIndex, mIndexWriterConfig);

			// Iterate on the document and add all of them to the indexe
			for (String id : docsList.keySet()) {
				String body = docsList.get(id);
				addDoc(body, id);
			}
			mTotalNumOfDocument = mIndexWriter.numDocs();
			mIndexWriter.close();
		} catch (Exception exception) {
			Log.error(TAG, exception, true);
		}
	}

	public SearchResult search(String searchQuery) throws IOException,
			ParseException {

		int hitsPerPage = 10;

		Query query = new QueryParser(Version.LUCENE_48, NAME_BODY, mAnalyzer)
				.parse(searchQuery);

		mIndexReader = DirectoryReader.open(mIndex);
		mIndexSearcher = new IndexSearcher(mIndexReader);

		mIndexSearcher.setSimilarity(mTfidfSimilarity);
		TopScoreDocCollector collector = TopScoreDocCollector.create(
				hitsPerPage, true);
		mIndexSearcher.search(query, collector);
		SearchResult result = new SearchResult(collector.topDocs().scoreDocs,
				mIndexSearcher, mTotalNumOfDocument);
		return result;
	}

	private void addDoc(String body, String id) throws IOException {

		/*
		 * should be remove: show the token created by the tokenizer {
		 * ArrayList<String> result = new ArrayList<String>(); TokenStream
		 * stream = mAnalyzer.tokenStream(null, new StringReader(body));
		 * 
		 * stream.reset(); while(stream.incrementToken()) {
		 * result.add(stream.getAttribute(CharTermAttribute.class).toString());
		 * } stream.close(); }
		 */
		Document doc = new Document();
		TextField docBody = new TextField(NAME_BODY, body, Field.Store.YES);
		StringField docId = new StringField(NAME_ID, id, Field.Store.YES);
		doc.add(docBody);
		doc.add(docId);
		mIndexWriter.addDocument(doc);
	}
	
	/**
	 * A method to get the doc corpus size
	 * @return The doc corpus size
	 */
	public int getDocCorpusSize(){
		return mTotalNumOfDocument;
	}
}